<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>嵌套聚合 | Elasticsearch: 权威指南 | Elastic</title>
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
</head>
<body>
<div class="main-container">
    <section id="content">
        
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原文地址: <a href="https://www.elastic.co/guide/cn/elasticsearch/guide/current/nested-aggregation.html" rel="nofollow">https://www.elastic.co/guide/cn/elasticsearch/guide/current/nested-aggregation.html</a>, 版权归 www.elastic.co 所有<br/>
                            英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-aggregation.html" rel="nofollow">https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-aggregation.html</a>
                            </div>
                        <!-- start body -->
                  <div class="page_header">
<b>请注意:</b><br>本书基于 Elasticsearch 2.x 版本，有些内容可能已经过时。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: 权威指南</a></span>
»
<span class="breadcrumb-link"><a href="modeling-your-data.html">数据建模</a></span>
»
<span class="breadcrumb-link"><a href="nested-objects.html">嵌套对象</a></span>
»
<span class="breadcrumb-node">嵌套聚合</span>
</div>
<div class="navheader">
<span class="prev">
<a href="nested-sorting.html">« 使用嵌套字段排序</a>
</span>
<span class="next">
<a href="parent-child.html">父-子关系文档 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="nested-aggregation"></a>嵌套聚合 (Nested Aggregations)<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/402_Nested/35_Nested_aggs.asciidoc">edit</a>
</h2>
</div></div></div>
<p>在查询的时候，我们使用 <code class="literal">nested</code> 查询  就可以获取嵌套对象的信息。同理， <code class="literal">nested</code> 聚合允许我们对嵌套对象里的字段进行聚合操作。</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">GET /my_index/blogpost/_search
{
  "size" : 0,
  "aggs": {
    "comments": { <a id="CO274-1"></a><i class="conum" data-value="1"></i>
      "nested": {
        "path": "comments"
      },
      "aggs": {
        "by_month": {
          "date_histogram": { <a id="CO274-2"></a><i class="conum" data-value="2"></i>
            "field":    "comments.date",
            "interval": "month",
            "format":   "yyyy-MM"
          },
          "aggs": {
            "avg_stars": {
              "avg": { <a id="CO274-3"></a><i class="conum" data-value="3"></i>
                "field": "comments.stars"
              }
            }
          }
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO274-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">nested</code>聚合 “进入” 嵌套的<code class="word">comments</code>对象。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO274-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p> comment 对象根据<code class="word">comments.date</code>字段的月份值被分到不同的桶。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO274-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p>计算每个桶内<code class="word">stars</code>的平均数量。</p>
</td>
</tr>
</table>
</div>
<p>从下面的结果可以看出聚合是在嵌套文档层面进行的：</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">...
"aggregations": {
  "comments": {
     "doc_count": 4, <a id="CO275-1"></a><i class="conum" data-value="1"></i>
     "by_month": {
        "buckets": [
           {
              "key_as_string": "2014-09",
              "key": 1409529600000,
              "doc_count": 1, <a id="CO275-2"></a><i class="conum" data-value="1"></i>
              "avg_stars": {
                 "value": 4
              }
           },
           {
              "key_as_string": "2014-10",
              "key": 1412121600000,
              "doc_count": 3, <a id="CO275-3"></a><i class="conum" data-value="1"></i>
              "avg_stars": {
                 "value": 2.6666666666666665
              }
           }
        ]
     }
  }
}
...</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO275-1"><i class="conum" data-value="1"></i></a><a href="#CO275-2"></a><a href="#CO275-3"></a></p>
</td>
<td align="left" valign="top">
<p>总共有4个 <code class="word">comments</code> 对象 ：1个对象在9月的桶里，3个对象在10月的桶里。</p>
</td>
</tr>
</table>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="reverse-nested-aggregation"></a>逆向嵌套聚合 (reverse_nested Aggregation)<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/402_Nested/35_Nested_aggs.asciidoc">edit</a>
</h3>
</div></div></div>
<p><code class="literal">nested</code> 聚合只能对嵌套文档的字段进行操作。
根文档或者其他嵌套文档的字段对它是不可见的。
然而，通过 <code class="literal">reverse_nested</code> 聚合，我们可以 <em>走出</em> 嵌套层级，回到父级文档进行操作。</p>

<p>例如，我们要基于评论者的年龄找出评论者感兴趣<code class="word">tags</code>的分布。<code class="word">comment.age</code>是一个嵌套字段，但<code class="word">tags</code>在根文档中：</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">GET /my_index/blogpost/_search
{
  "size" : 0,
  "aggs": {
    "comments": {
      "nested": { <a id="CO276-1"></a><i class="conum" data-value="1"></i>
        "path": "comments"
      },
      "aggs": {
        "age_group": {
          "histogram": { <a id="CO276-2"></a><i class="conum" data-value="2"></i>
            "field":    "comments.age",
            "interval": 10
          },
          "aggs": {
            "blogposts": {
              "reverse_nested": {}, <a id="CO276-3"></a><i class="conum" data-value="3"></i>
              "aggs": {
                "tags": {
                  "terms": { <a id="CO276-4"></a><i class="conum" data-value="4"></i>
                    "field": "tags"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO276-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">nested</code>聚合进入<code class="word">comments</code>对象。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO276-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">histogram</code>聚合基于<code class="word">comments.age</code>做分组，每10年一个分组。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO276-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">reverse_nested</code>聚合退回根文档。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO276-4"><i class="conum" data-value="4"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">terms</code> 聚合计算每个分组年龄段的评论者最常用的标签词。</p>
</td>
</tr>
</table>
</div>
<p>简略结果如下所示：</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">..
"aggregations": {
  "comments": {
     "doc_count": 4, <a id="CO277-1"></a><i class="conum" data-value="1"></i>
     "age_group": {
        "buckets": [
           {
              "key": 20, <a id="CO277-2"></a><i class="conum" data-value="2"></i>
              "doc_count": 2, <a id="CO277-3"></a><i class="conum" data-value="2"></i>
              "blogposts": {
                 "doc_count": 2, <a id="CO277-4"></a><i class="conum" data-value="3"></i>
                 "tags": {
                    "doc_count_error_upper_bound": 0,
                    "buckets": [ <a id="CO277-5"></a><i class="conum" data-value="4"></i>
                       { "key": "shares",   "doc_count": 2 },
                       { "key": "cash",     "doc_count": 1 },
                       { "key": "equities", "doc_count": 1 }
                    ]
                 }
              }
           },
...</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO277-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>一共有4条评论。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO277-2"><i class="conum" data-value="2"></i></a><a href="#CO277-3"></a></p>
</td>
<td align="left" valign="top">
<p>在20岁到30岁之间总共有两条评论。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO277-4"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p>这些评论包含在两篇博客文章中。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO277-5"><i class="conum" data-value="4"></i></a></p>
</td>
<td align="left" valign="top">
<p>在这些博客文章中最热门的标签是<code class="word">shares</code>、<code class="word">cash</code>、<code class="word">equities</code>。</p>
</td>
</tr>
</table>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_嵌套对象的使用时机"></a>嵌套对象的使用时机<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/402_Nested/35_Nested_aggs.asciidoc">edit</a>
</h3>
</div></div></div>
<p>嵌套对象<b>在只有一个主要实体时非常有用</b>，这个主要实体包含有限个紧密关联但又不是很重要的实体，例如我们的 <code class="word">blogpost</code> 对象包含评论对象。
在基于评论的内容查找博客文章时， <code class="literal">nested</code> 查询有很大的用处，并且可以提供更快的查询效率。</p>
<p>嵌套模型的缺点如下：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
当对嵌套文档做增加、修改或者删除时，整个文档都要重新被索引。嵌套文档越多，这带来的成本就越大。
</li>
<li class="listitem">
查询结果返回的是整个文档，而不仅仅是匹配的嵌套文档。尽管目前有计划支持只返回根文档中最佳匹配的嵌套文档，但目前还不支持。
</li>
</ul>
</div>
<p>有时你需要在主文档和其关联实体之间做一个完整的隔离设计。这个隔离是由 <em>父子关联</em> 提供的。</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="nested-sorting.html">« 使用嵌套字段排序</a>
</span>
<span class="next">
<a href="parent-child.html">父-子关系文档 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>